package cate.game.role.farm.rank;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDRank;
import cate.common.table.rank.row.IRewardRankRow;
import cate.common.table.rank.row.RankBaseRow;
import cate.common.util.GameResult;
import cate.game.client.msg.MergeMsgSender;
import cate.game.pvp.ladder.common.LadderAdmireResult;
import cate.game.pvp.ladder.common.LadderRankAdmireQuery;
import cate.game.pvp.ladder.common.LadderRankListQuery;
import cate.game.pvp.ladder.common.LadderRankListResult;
import cate.game.pvp.ladder.msg.LadderRankResp;
import cate.game.rank.IRewardRankObj;
import cate.game.rank.h.IConditionRankHandler;
import cate.game.rank.h.IRankFuncHandler;
import cate.game.rank.history.RankReachHistory;
import cate.game.rank.msg.*;
import cate.game.rank.po.Rank;
import cate.game.rank.vo.RankParam;
import cate.game.rank.vo.RankRange;
import cate.game.res.MixRes;
import cate.game.role.FuncOpenChecker;
import cate.game.role.Role;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.GuildRankItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.springframework.data.annotation.Transient;

import java.util.*;
import java.util.stream.Collectors;

public class RoleRank extends FuncOpenChecker {
    @JsonIgnore
    @Transient
    private transient Map<Integer, IRewardRankObj> objs;

    @NoteField(value = "偷懒用的，自带排行榜领奖")
    public Map<Integer, UnrealRankObj> unrealObjs;

    @NoteField(value = "点赞专用")
    public UnrealAdmireObj unrealAdmire;

    @NoteField("被点赞的次数")
    public Map<Integer, Integer> beAdmires;

    public RoleRank() {

    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (objs == null) {
            objs = new HashMap<>();
        }
        if (unrealObjs == null) {
            unrealObjs = new HashMap<>();
        }
        unrealObjs.values().forEach(e -> e.initialize(role));
        if (unrealAdmire == null) {
            unrealAdmire = new UnrealAdmireObj();
        }
        unrealAdmire.initialize(role);
        if (beAdmires == null) {
            beAdmires = new HashMap<>();
        }
        initializeObjs();
    }

    @Override
    public int getFuncId() {
        return GDFunc.RANK;
    }

    @Override
    public void onAfterOpen() {
        noticeUpdate();
    }

    public void noticeUpdate() {
        if (isOpen()) {
            role.sendNow(new RankRedPointDataResp(getRedPointRanks()));
        }
    }

    public List<Integer> getRedPointRanks() {
        List<Integer> list = new ArrayList<>();
        try {
            for (Integer rankId : objs.keySet()) {
                if (hasReward(rankId) && needNotice(rankId)) {
                    list.add(rankId);
                }
            }
        } catch (Exception e) {
            //
        }
        return list;
    }

    private void initializeObjs() {
        if (objs.isEmpty()) {
            for (RankBaseRow row : role.getGame().table.rank.base.getList()) {
                if (row.canGetReward && unrealObjs.get(row.id) == null) {
                    unrealObjs.put(row.id, new UnrealRankObj(role, row.id));
                }
                IRewardRankObj obj = unrealObjs.get(row.id);
                if (obj != null) {
                    objs.put(row.id, obj);
                }
            }
        }
    }

    private boolean hasReward(int rankId) {
        return role.getGame().table.rank.hasReward(rankId);
    }

    private boolean needNotice(int rankId) {
        IRewardRankObj obj = objs.get(rankId);
        if (obj != null && obj.isOpen()) {
            Map<Integer, RankReachHistory> historys = role.getGame().rank.getRankHistory(rankId);
            return historys.values().stream().filter(e -> role.getGame().table.rank.canRedPoint(e.rankId, e.rewardId, role.getBase().level)).count() > obj.getRewardsMap().size();
        }
        return false;
    }

    public void noticeUpdate(int rankId) {
        if (isOpen() && needNotice(rankId)) {
            role.sendNow(new RankRedPointDataResp(Collections.singletonList(rankId)));
        }
    }

    /**
     * 领取排行榜奖励
     *
     * @param rankId   排行榜
     * @return r
     */
    public GameResult<Void> getRankReward(int rankId) {
        GameResult<Void> r = new GameResult<>();
        RankBaseRow base = role.getGame().table.rank.base.get(rankId);
        if (base == null || !base.canGetReward) {
            return r.fail("该榜单不可领奖");
        }
        IRewardRankObj obj = objs.get(rankId);
        if (obj == null) {
            return r.fail("不存在的榜单");
        }
        if (!obj.isOpen()) {
            return r.fail("功能未开启");
        }
        IRankFuncHandler<? extends Rank> handler = role.getGame().rank.getRankHandler(rankId);
        if (handler == null) {
            return r.fail("不存在的榜单");
        }
        List<Integer> rewards = role.getGame().rank.getRankHistory(rankId).values().stream().map(e -> e.rewardId).collect(Collectors.toList());
        if (rewards.isEmpty()) {
            return r.fail("没有奖励可以领取");
        }
        MixRes reward = new MixRes();
        List<Integer> rewardIds = new ArrayList<>();
        MergeMsgSender sender = new MergeMsgSender();
        for (Integer rewardId : rewards) {
            IRewardRankRow row = role.getGame().table.rank.getRewardRow(rankId, rewardId);
            if (row == null) {
                continue;
            }
            if (row.getLevelLimit() > role.getBase().level) {
                continue;
            }
            if (obj.getRewardsMap().containsKey(rewardId)) {
                continue;
            }
            reward.addList(obj.getRankReward(row, false, sender));
            rewardIds.add(rewardId);
        }
        if (rewardIds.isEmpty()) {
            return r.fail("没有奖励可以领取");
        }
        sender.send(role, true);
        role.getGame().notice.dialogReward(role, reward);
        role.sendNow(new RankRewardResp(rankId, rewardIds));
        return r;
    }

    /**
     * 点赞
     *
     * @param rankId 排行榜id
     * @param rank   排名
     * @return
     */
    public GameResult<Void> admire(int rankId, int rank) {
        GameResult<Void> r = new GameResult<>();
        RankBaseRow base = role.getGame().table.rank.base.get(rankId);
        if (base == null || !base.canAdmire) {
            return r.fail("该榜单不可点赞");
        }
        if ( unrealAdmire.getAdmireTimes(rankId) >= GDRank.DAILY_ADMIRE_TIMES) {
            return r.fail("每日只可点赞{}次,请明天再来", GDRank.DAILY_ADMIRE_TIMES);
        }
        if (rankId == GDRank.Id.LADDER_RACE_RANK_ID) {
            LadderRankAdmireQuery query = new LadderRankAdmireQuery();
            query.rank = rank + 1;
            LadderAdmireResult result = role.getGame().pvp.ladder.admire(query);
            if (!result.ok()) {
                return r.fail("天梯赛点赞失败 ，"+result.em);
            }
            unrealAdmire.admireLadder();
        } else {
            IRankFuncHandler<? extends Rank> handler = role.getGame().rank.getRankHandler(rankId);
            if (handler == null) {
                return r.fail("不存在的榜单");
            }
            EcResult<Void> admireRes = handler.admire(RankParam.build(role), role.getUid(), rank);
            if (!admireRes.ok()) {
                return r.fail(admireRes);
            }
            if (rankId == GDRank.Id.CHAMPION_RACE_RANK_ID) {
                unrealAdmire.admireChampionRace();
            } else {
                unrealAdmire.admire(rank);
            }
        }
        role.sendNow(new RankAdmireResp(rankId, rank + 1, unrealAdmire.getAdmireTimes(rankId)));
        return r;
    }

    /**
     * 获取排行榜功能的数据
     */
    public void getRankData() {
        Map<Integer, Object> data = new HashMap<>();
        for (RankBaseRow baseRow : role.getGame().table.rank.base.getList()) {
            if (baseRow != null && baseRow.enter) {
                IRankFuncHandler<? extends Rank> handler = role.getGame().rank.getRankHandler(baseRow.id);
                if (handler != null) {
                    Rank rankOne = handler.getRankOneData(RankParam.build(role));
                    if (rankOne != null) {
                        data.put(handler.getRankId(), rankOne);
                    }
                }
            }
        }
        //协会特殊处理
        List<GuildPO> totalRank = role.getGame().res.guild.getRank();
        GuildPO guild = totalRank.isEmpty() ? null : totalRank.get(0);
        data.put(GDRank.Id.GUILD_RANK_ID, guild == null ? null : new GuildRankItem(
                guild.uid, guild.active.activity, guild.basic));
        role.sendNow(new RankDataResp(data));
    }

    /**
     * 获取单个排行榜数据
     *
     * @param rankId 排行榜id
     * @return r
     */
    public GameResult<Void> getSingleRankData(int rankId, int limit) {
        GameResult<Void> r = new GameResult<>();
        RankBaseRow base = role.getGame().table.rank.base.get(rankId);
        if (base == null) {
            return r.fail("不存在的榜单");
        }
        if (rankId == GDRank.Id.LADDER_RACE_RANK_ID) {
            LadderRankListQuery query = new LadderRankListQuery();
            query.roleId = role.getUid();
            query.limit = limit;
            LadderRankListResult result = role.getGame().pvp.ladder.getRankList(query);
            role.sendNow(new LadderRankResp(rankId, result.myRank, result.self, result.list, unrealAdmire.getAdmireTimes(rankId)));
            return r.success();
        } else if (base.type == RankBaseRow.CROSS && rankId != GDRank.Id.CHAMPION_RACE_RANK_ID) {
            return role.getGame().crossRank.sendCrossSingleRankData(role, rankId, limit);
        }
        IRankFuncHandler<? extends Rank> handler = role.getGame().rank.getRankHandler(rankId);
        if (handler == null) {
            return r.fail("不存在的榜单");
        }
        //obj是可以为空的，当又不需要点赞，又不需要领奖的时候
        IRewardRankObj obj = objs.get(rankId);
        if (base.canGetReward && obj == null) {
            return r.fail("不存在的榜单");
        }
        if (obj != null && !obj.isOpen()) {
            return r.fail("功能未开启");
        }
        Rank my = handler.getData(RankParam.build(role), role);
        List<? extends Rank> rankList = new RankRange(limit).getRankList(handler.getRankList(RankParam.build(role)));
        int myRank = -1;
        for (int i = 0; i < rankList.size(); ++i) {
            if (role.getUid().equals(rankList.get(i).owner.uid)) {
                if (my == null) {
                    my = rankList.get(i);
                }
                myRank = i + 1;
                break;
            }
        }
        if (my == null) {
            long defaultValue = 0L;
            if (handler instanceof IConditionRankHandler) {
                defaultValue = ((IConditionRankHandler) handler).getRoleCurrentValue(role);
            }
            my = new Rank(role, defaultValue);
        }
        role.sendNow(new SingleRankDataResp(rankId, myRank, my, rankList, obj == null ? 0 : unrealAdmire.getAdmireTimes(rankId)));
        return r;
    }

    public GameResult<Void> getRankRewardData(int rankId) {
        GameResult<Void> r = new GameResult<>();
        RankBaseRow base = role.getGame().table.rank.base.get(rankId);
        if (base == null) {
            return r.fail("不存在的榜单");
        }
        if (!base.canGetReward) {
            return r.fail("该榜单没有奖励可领取");
        }
        IRewardRankObj obj = objs.get(rankId);
        if (obj == null) {
            return r.fail("不存在的榜单");
        }
        role.sendNow(new SingleRankRewardDataResp(rankId, obj.getRewardsMap(), role.getGame().rank.getRankHistory(rankId)));
        return r;
    }

    @Override
    public void onDaySpan(boolean silence) {
        unrealAdmire.onDaySpanSafe(silence);
    }

    public void beAdmire(int rankId) {
        beAdmires.putIfAbsent(rankId, 0);
        beAdmires.put(rankId, beAdmires.get(rankId) + 1);
    }
}
